#include <iostream>
#include <fstream>
#include <stdexcept>
#include "local_minimizer_implementation.h"

class FunctionOfInterest : public local_minimizer::Function
{
private:
	double alpha_;

	static double penalty(const Vector& x)
	{
		const double constraint=0.1;
		if(x[1]>=constraint) { return 0.0; }
		else { return 1.0*(exp(pow(constraint-x[1], 2))-1);}
	}

public:
	FunctionOfInterest(const double alpha) : alpha_(alpha) {}

	double operator() (const Vector& x) const
	{
		return ( pow(x[0]-x[1], 2.0) + pow(x[0], 4.0)*pow(x[1]-0.5, 2.0) + 2.0*pow(x[2]-x[1]+alpha_, 2.0) + penalty(x));
	}
};

struct Configuration
{
	double alpha;
	Vector start;

	Configuration(int argc, const char** argv) : alpha(0.0), start(3)
	{
		if(argc>=2)
		{
			std::ifstream input(argv[1], std::ios::in);
			if(!input.good()) { throw std::runtime_error("Failed to open input file"); }
			input >> alpha;
			for(std::size_t i=0;i<start.length();i++) { input >> start[i]; }
		}
		else
		{
			throw std::invalid_argument("Missing arguments");
		}
	}
};

int main(int argc, const char** argv)
{
	try
	{
		Configuration conf(argc, argv);
		FunctionOfInterest function(conf.alpha);
		Vector start=conf.start;
		local_minimizer_implementation::AxisChangingDirector director;
		local_minimizer_implementation::GoldenSearcher searcher(1.0, 0.0001);
		local_minimizer_implementation::ConvergenceChecker checker(0.000001, 50);
		local_minimizer::local_minimizer(function, start, director, searcher, checker);
	}
	catch(const std::exception& e)
	{
		std::cerr << "Exception: " << e.what() << "\n";
	}

	return 0;
}
